/*--------------------------------------------------------------------------------------*\
**
** castle_window.cpp
**
** Heroes IV
** Copyright 2000, The 3DO Company
**
\*--------------------------------------------------------------------------------------*/

// kill the 255+ character identifier warning.  Templates tend to exceed that easily.
#include "precompiled.h"
#pragma warning( disable: 4786 )

#include "castle_window.h"

#include "abbreviate_number.h"
#include "adaptor_handler.h"
#include "adventure_map.h"
#include "adventure_sounds.h"
#include "army.h"
#include "artifact_keyword.h"
#include "artifact_type.h"
#include "artifact_properties.h"
#include "basic_dialog.h"
#include "bitmap_group_cache.h"
#include "bitmap_group_ptr.h"
#include "bitmap_group_window.h"
#include "blended_bitmap_window.h"
#include "bound_handler.h"
#include "building_traits.h"
#include "button.h"
#include "button_cache.h"
#include "combat_model_window.h"
#include "creature.h"
#include "creature_array_window.h"
#include "creature_detail_display.h"
#include "creature_traits.h"
#include "creature_type.h"
#include "dialog_creature_portal.h"
#include "enum_operations.h"
#include "external_string.h"
#include "format_string.h"
#include "game_replace_keywords.h"
#include "hero.h"
#include "interface_help.h"
#include "material_icons.h"
#include "music.h"
#include "platform.h"
#include "player.h"
#include "recruit_dialog.h"
#include "simple_dialog.h"
#include "skill_icon.h"
#include "standard_fonts.h"
#include "string_insensitive_compare.h"
#include "text_window.h"
#include "toggle_button.h"
#include "town.h"
#include "town_properties.h"
#include "town_window.h" // for check_garrison_space()

extern	t_external_string const k_hotkey_buy;
extern t_button_cache const     k_buy_button;
extern t_button_cache           g_max_button;
extern t_button_cache           g_ok_button;
extern t_bitmap_group_cache     g_material_icons;

t_bitmap_group_cache     k_castle_background_bitmaps ("dialog.castle_screen");
t_bitmap_group_cache     k_icon_stats_27 ("icons.stats.27");
static t_external_string const k_text_not_enough_gold( "not_enough_resources.castle_window" );
static t_external_string const k_text_not_enough_slots( "not_enough_slots.castle_window" );
static t_external_string const k_text_not_enough_creatures( "not_enough_creatures.castle_window" );
static t_external_string const k_text_weekly_growth( "weekly_growth.castle_window" );
static t_external_string const k_text_creatures_recruited( "creatures_recruited.castle_window" );
extern t_external_string const  k_text_not_applicable;
static const int k_max_display_skills = 4;

/*---------------------------------------------------------------------------------------*\
**
** Castle window constructor - recruit creatures.
**
\*---------------------------------------------------------------------------------------*/
t_castle_window::t_castle_window( t_town* town, t_town_window* parent, int discount )
                   : t_window( k_completely_transparent, parent )
{
	t_screen_rect   rect;
	t_screen_rect   parent_rect;
    int             window_index=0;

    m_town_window = parent;

    /*
    ** Init values.
    */
	m_town = town;
	t_adventure_map & map = *m_town->get_map();
	m_player_ptr = &map.get_player(); //m_adj_army_ptr->get_owner(); 
	m_player_funds = m_player_ptr->get_funds()[k_gold];
	m_discount = discount;
    m_num_windows = 0;

	// add creature portal
	if (m_town->has( k_town_portal ))
    {
        m_show_portal = true;
    }
    else
    {
        m_show_portal = false;
    }

	/*
    ** Load bitmaps, set position.
    */
	m_background_bitmaps_ptr = k_castle_background_bitmaps.get();
	parent_rect = get_parent()->get_client_rect();
	rect = m_background_bitmaps_ptr->get_rect();
	rect += (parent_rect.size() - rect.size()) / 2;
	init( rect );

	/*
    ** Create background.
    */
	t_bitmap_layer const*   layer;
	t_window*               window_ptr;
	t_window*               background_ptr;
	t_screen_point          origin(0,0);
	std::string             frame_name;

	layer = m_background_bitmaps_ptr->find( "background" );
	background_ptr = new t_bitmap_layer_window( layer, origin, this );
	origin = -layer->get_rect().top_left();

	t_bitmap_layer const*   creature_layer;
	t_bitmap_layer const*   blank_layer;
    t_screen_point          frame_offset(0,0);
    t_screen_point          creature_frame_offset(0,0);
	t_town_building         dwelling;
	t_town_type             town_type = m_town->get_type();

    frame_offset = m_background_bitmaps_ptr->find( "monster_1" )->get_rect().top_left();
	creature_layer = m_background_bitmaps_ptr->find( "creature_background" );
	blank_layer = m_background_bitmaps_ptr->find( "blank_background" );
    creature_frame_offset = creature_layer->get_rect().top_left() - frame_offset;
    creature_frame_offset = -creature_layer->get_rect().top_left();

    window_index = 0;
	for (dwelling = k_town_dwelling_1; dwelling <= k_town_dwelling_8; enum_incr(dwelling))
	{
		if (!m_town->has( dwelling ))
			continue;

		t_building_traits const& bld_traits = get_traits( town_type, dwelling );
        if (window_index < k_num_top_windows)
        {
    	    frame_name = format_string( "monster_%d", (window_index+1) );
        }
        // Middle row - check 5 or 6.
        else
        {
            if (m_show_portal)
    	        frame_name = format_string( "monster_%d_of_6", (window_index+1) );
            else
        	    frame_name = format_string( "monster_%d_of_5", (window_index+1) );
        }
        
        rect = m_background_bitmaps_ptr->find( frame_name )->get_rect();
	    window_ptr = new t_bitmap_layer_window( creature_layer, rect.top_left() + creature_frame_offset, this );

		// Show creature for this dwelling
        create_creature_window( rect, bld_traits.creature, dwelling, 
								m_town->get_population( bld_traits.creature ), window_index );
        m_num_windows++;

        // Recruit click handler.
	    m_buttons[window_index]->set_click_handler( add_2nd_argument( bound_handler( *this, 
                                               			        &t_castle_window::recruit_creatures), window_index ) );

        window_index++;
	}

    // Fill the rest with blanks.
    while (window_index < k_max_creature_windows)
    {
        if (window_index < k_num_top_windows)
        {
    	    frame_name = format_string( "monster_%d", (window_index+1) );
        }
        // Middle row - check 5 or 6.
        else
        {
            if (m_show_portal)
    	        frame_name = format_string( "monster_%d_of_6", (window_index+1) );
            else
        	    frame_name = format_string( "monster_%d_of_5", (window_index+1) );
        }
        
        rect = m_background_bitmaps_ptr->find( frame_name )->get_rect();

	    window_ptr = new t_bitmap_layer_window( blank_layer, rect.top_left() + creature_frame_offset, this );
        window_index++;
    }

    // Portal.
    if (m_show_portal)
    {
        // Portal window.
        rect = m_background_bitmaps_ptr->find( "monster_6_of_6" )->get_rect();
	    window_ptr = new t_bitmap_layer_window( creature_layer, rect.top_left() + creature_frame_offset, this );

		// Show creature for this dwelling
        create_creature_window( rect, m_town->get_portal_creature(), k_town_portal,
								m_town->get_portal_population(), k_portal_number );

        m_buttons[k_portal_number]->set_click_handler( bound_handler( *this, &t_castle_window::recruit_portal) );
    }

	layer = m_background_bitmaps_ptr->find( "resource_layer" );
	window_ptr = new t_bitmap_layer_window( layer, origin, this );

	std::string     material_amount_text;
    int             i;
    for (i=0; i<k_material_count; i++)
    {
		material_amount_text = format_string ( "text_%s", k_material_keyword[i] );
    	rect = m_background_bitmaps_ptr->find( material_amount_text )->get_rect();
		m_material_text[i] = new t_text_window( get_font( rect.height() ), rect, this, "", t_pixel_24(0,0,0) );
        m_material_text[i]->set_center_horizontal();
    }
    material_update();

    /*
    ** Create buttons.
    */
	t_button            *button_ptr;
	t_help_block const& help = get_help_block( "castle" );

	// Create buy all button
	rect = m_background_bitmaps_ptr->find( "purchase_all_button" )->get_rect();
	button_ptr = new t_button( g_max_button.get(), rect.top_left(), this );
	if ( map.get_player_number() != m_town->get_owner_number() )
	{
		button_ptr->enable( false );
	}
	else
	{
		button_ptr->set_click_handler( bound_handler( *this, &t_castle_window::purchase_all_click ));
	}
   	set_help( button_ptr, help, "maximum" );
	
	// Create close button
	rect = m_background_bitmaps_ptr->find( "close_button" )->get_rect();
	button_ptr = new t_button( g_ok_button.get(), rect.top_left(), this );
	button_ptr->set_click_handler( bound_handler( *this, &t_castle_window::close_click ));
	set_help( button_ptr, help, "ok" );
}

// Update material amount text.
void t_castle_window::material_update()
{
	int                     i;
	t_material_array const& funds = m_player_ptr->get_funds();

	for (i = 0; i < k_material_count; i++)
	{
		if (m_material_text[i] == 0)
			continue;

		m_material_text[i]->set_text( abbreviate_number( funds[i],
														 *m_material_text[i]->get_font(),
														 m_material_text[i]->get_width()));
	}
    m_town_window->update_materials();
}

/*
** Create creature window.
*/
void t_castle_window::create_creature_window( t_screen_rect&	creature_rect, 
											  t_creature_type	creature, 
											  t_town_building	building,
											  int				creature_amount, 
											  int				window_index )
{
	t_screen_rect   rect;
	t_screen_rect   origin_rect = m_background_bitmaps_ptr->find( "Monster_1" )->get_rect();
	t_screen_point  origin_offset = -origin_rect.top_left() + creature_rect.top_left();
	std::string     display_text;
    int             count = 0;
    int             i = 0;
    t_creature_traits const& creature_traits = get_traits( creature );
	t_castle_creature_window&	creature_window = m_creature_windows[window_index];

    m_creature_windows[window_index].creature_type = creature;
	rect = m_background_bitmaps_ptr->find( "creature_name" )->get_rect() + origin_offset;
    m_creature_windows[window_index].creature_num = new t_text_window( get_font( 14 ), rect,
													this, "", t_pixel_24(0,0,0) );
    m_creature_windows[window_index].creature_num->set_center_horizontal();
    m_creature_windows[window_index].creature_num->set_center_vertical();

	rect = m_background_bitmaps_ptr->find( "creature_growth" )->get_rect() + origin_offset;
    m_creature_windows[window_index].creature_growth = new t_text_window( get_font( 12 ), rect, this, "", t_pixel_24(0,0,0) );
    m_creature_windows[window_index].creature_growth->set_center_horizontal();
    m_creature_windows[window_index].creature_growth->set_center_vertical();

    // Animation window.
    t_window*				holder;

    rect = m_background_bitmaps_ptr->find( "animation" )->get_rect();
    m_buttons[window_index] = new t_button( rect.top_left() + origin_offset, this );
	holder = new t_window( t_screen_rect(0,0,0,0), t_window::k_completely_transparent, m_buttons[window_index] );
    rect -= rect.top_left();
    m_creature_windows[window_index].anim_window_ptr = new t_combat_model_window( rect, holder );
    m_creature_windows[window_index].anim_window_ptr->set( m_town->get_type() );
    m_creature_windows[window_index].anim_window_ptr->set ( creature );
	holder->set_size_from_children();
    m_buttons[window_index]->set_released_image (holder);

    // Add skill icons and text.
	t_bitmap_layer const*   layer;
	t_window*               window_ptr;
	t_help_block const&     shared_help = get_help_block( "shared" );
	t_help_block const&     help = get_help_block( "army_screen" );

    // Damage - add offset.
	layer = m_background_bitmaps_ptr->find( "damage" );
	window_ptr = new t_bitmap_layer_window( layer, origin_offset, this );
	set_help( window_ptr, shared_help, "damage" );
    rect = m_background_bitmaps_ptr->find( "damage_text" )->get_rect() + origin_offset;
	m_creature_windows[window_index].damage = new t_text_window( get_font( 12 ), rect, this,
                    "", t_pixel_24(0,0,0) ); 
    m_creature_windows[window_index].damage->set_center_horizontal();

	layer = m_background_bitmaps_ptr->find( "melee_attack" );
	window_ptr = new t_bitmap_layer_window( layer, origin_offset, this );
	set_help( window_ptr, help, "melee_attack" );
    rect = m_background_bitmaps_ptr->find( "melee_attack_text" )->get_rect() + origin_offset;
	m_creature_windows[window_index].melee_offense = new t_text_window( get_font( 12 ), rect, this,
                    "", t_pixel_24(0,0,0) ); 
    m_creature_windows[window_index].melee_offense->set_center_horizontal();

	layer = m_background_bitmaps_ptr->find( "melee_defense" );
	window_ptr = new t_bitmap_layer_window( layer, origin_offset, this );
	set_help( window_ptr, help, "melee_defense" );
    rect = m_background_bitmaps_ptr->find( "melee_defense_text" )->get_rect() + origin_offset;
	m_creature_windows[window_index].melee_defense = new t_text_window( get_font( 12 ), rect, this,
                    "", t_pixel_24(0,0,0) ); 
    m_creature_windows[window_index].melee_defense->set_center_horizontal();

	layer = m_background_bitmaps_ptr->find( "hit_points" );
	window_ptr = new t_bitmap_layer_window( layer, origin_offset, this );
	set_help( window_ptr, shared_help, "hit_points" );
    rect = m_background_bitmaps_ptr->find( "hit_points_text" )->get_rect() + origin_offset;
	m_creature_windows[window_index].hit_points = new t_text_window( get_font( 12 ), rect, this,
                    "", t_pixel_24(0,0,0) ); 
    m_creature_windows[window_index].hit_points->set_center_horizontal();

	layer = m_background_bitmaps_ptr->find( "ranged_attack" );
	window_ptr = new t_bitmap_layer_window( layer, origin_offset, this );
	set_help( window_ptr, help, "ranged_attack" );
    rect = m_background_bitmaps_ptr->find( "ranged_attack_text" )->get_rect() + origin_offset;
	m_creature_windows[window_index].ranged_offense = new t_text_window( get_font( 12 ), rect, this,
                    "", t_pixel_24(0,0,0) ); 
    m_creature_windows[window_index].ranged_offense->set_center_horizontal();

	layer = m_background_bitmaps_ptr->find( "ranged_defense" );
	window_ptr = new t_bitmap_layer_window( layer, origin_offset, this );
	set_help( window_ptr, help, "ranged_defense" );
    rect = m_background_bitmaps_ptr->find( "ranged_defense_text" )->get_rect() + origin_offset;
	m_creature_windows[window_index].ranged_defense = new t_text_window( get_font( 12 ), rect, this,
                    "", t_pixel_24(0,0,0) ); 
    m_creature_windows[window_index].ranged_defense->set_center_horizontal();

	layer = m_background_bitmaps_ptr->find( "shots" );
	window_ptr = new t_bitmap_layer_window( layer, origin_offset, this );
	set_help( window_ptr, shared_help, "shots" );
    rect = m_background_bitmaps_ptr->find( "shots_text" )->get_rect() + origin_offset;
	m_creature_windows[window_index].shots = new t_text_window( get_font( 12 ), rect, this,
                    "", t_pixel_24(0,0,0) );
    m_creature_windows[window_index].shots->set_center_horizontal();

	layer = m_background_bitmaps_ptr->find( "speed" );
	window_ptr = new t_bitmap_layer_window( layer, origin_offset, this );
	set_help( window_ptr, shared_help, "speed" );
    rect = m_background_bitmaps_ptr->find( "speed_text" )->get_rect() + origin_offset;
	m_creature_windows[window_index].speed = new t_text_window( get_font( 12 ), rect, this,
                    "", t_pixel_24(0,0,0) ); 
    m_creature_windows[window_index].speed->set_center_horizontal();

	layer = m_background_bitmaps_ptr->find( "movement" );
	window_ptr = new t_bitmap_layer_window( layer, origin_offset, this );
	set_help( window_ptr, shared_help, "movement" );
    rect = m_background_bitmaps_ptr->find( "movement_text" )->get_rect() + origin_offset;
	m_creature_windows[window_index].movement = new t_text_window( get_font( 12 ), rect, this,
                    "", t_pixel_24(0,0,0) ); 
    m_creature_windows[window_index].movement->set_center_horizontal();

    // Show cost.
	m_material_icons = g_material_icons.get();
	for (i = 0; i < k_max_material_costs; ++i)
	{
        rect = m_background_bitmaps_ptr->find( format_string("resource_%d", i+1) )->get_rect();
        rect += origin_offset;

		creature_window.cost_icon[i] = new t_bitmap_layer_window( 0, rect.top_left(), this );

        rect = m_background_bitmaps_ptr->find( format_string("resource_%d_text", i+1) )->get_rect();
        rect += origin_offset;
	    creature_window.cost_text[i] = new t_text_window( get_font( 12 ), rect, this, "", 
											           t_pixel_24(0,0,0) ); 
        creature_window.cost_text[i]->set_center_horizontal();
	}

    // Show skills.
	t_skill_icon_ptr skill_icon_ptr;
    std::vector<t_creature_ability> abilities = creature_traits.abilities;
    t_screen_point point;

	for (i = 0; i < k_max_display_skills; i++)
    {
        rect = t_screen_rect(0, 0, 52, 52);
	    point = m_background_bitmaps_ptr->find(format_string( "ability_%i", i+1))->get_rect().top_left();
        rect += point;
        rect += origin_offset;
	    m_creature_windows[window_index].m_skill_icons[i] = new t_skill_icon( rect, this );
    }

    layer = m_background_bitmaps_ptr->find( "abilities_frame" );
	window_ptr = new t_bitmap_layer_window( layer, origin_offset, this );

    update_creature_quantity( creature_window, creature, creature_amount );
    update_creature_stats( m_creature_windows[window_index], creature, building );
}

// Update creature amount window.
void t_castle_window::update_creature_quantity( t_castle_creature_window &creature_window, t_creature_type const creature_type, int quantity )
{
	std::string             display_text;

	display_text = format_string( "%d %s", quantity,
                    get_creature_name( creature_type, quantity, false ).c_str(), t_pixel_24(0,0,0) );
    creature_window.creature_num->set_text( display_text );
    creature_window.creature_num->set_center_horizontal();
    creature_window.creature_num->set_center_vertical();
}

// Update creature amount window.
void t_castle_window::update_creature_stats( t_castle_creature_window&	creature_window,
											 t_creature_type			creature_type,
											 t_town_building			building )
{
	std::string					display_text;
	t_owned_ptr<t_creature>		creature_ptr( new t_creature( creature_type, 1 ) );
    t_creature_traits const&	creature_traits = get_traits( creature_type );

	int			            low_damage;
	int			            high_damage;

    creature_window.creature_type = creature_type;
	low_damage = creature_ptr->get_damage_low();
	high_damage = creature_ptr->get_damage_high();

    // Damage - add offset.
	creature_window.damage->set_text( format_string( "%i-%i", low_damage, high_damage )  );

	float melee_offense = creature_ptr->get_offense( false );
	display_text = format_string( "%i", int( melee_offense * 10.0f + 0.5f ) );
	creature_window.melee_offense->set_text( display_text );

	float melee_defense = creature_ptr->get_defense_basic( false );
	display_text = format_string( "%i", int( melee_defense * 10.0f + 0.5f ) );
	creature_window.melee_defense->set_text( display_text );

	creature_window.hit_points->set_text( format_string( "%i", creature_ptr->get_hit_points() ) );

	float ranged_attack = creature_ptr->get_offense( true );
	display_text = format_string( "%i", int( ranged_attack * 10.0f + 0.5f ) );
    creature_window.ranged_offense->set_text( display_text );

	float ranged_defense = creature_ptr->get_defense_basic( true );
	display_text = format_string( "%i", int( ranged_defense * 10.0f + 0.5f ) );
    creature_window.ranged_defense->set_text( display_text );
	
	if (creature_ptr->has_ability( k_ability_ranged ))
    {
        creature_window.shots->set_text( format_string( "%i", creature_ptr->get_shots() ) );
    }
    else
    {
        creature_window.shots->set_text( k_text_not_applicable );
    }

	creature_window.speed->set_text( format_string( "%i", creature_ptr->get_speed() ) );

	creature_window.movement->set_text( format_string( "%i", creature_traits.movement ) );
    
    creature_window.anim_window_ptr->set( creature_type );
    
    std::vector<t_creature_ability> const& abilities = creature_traits.abilities;

    int count = 0;
    for (count = 0; count < k_max_display_skills; count++)
    {
        if (count < abilities.size())
    	    creature_window.m_skill_icons[count]->set_ability ( abilities[count] );
        else
    	    creature_window.m_skill_icons[count]->set_ability ( k_ability_none );
    }

    int creature_cost;
	int	i;

	count = 0;
	for (i = 0; i < k_material_count; i++)
    {
        creature_cost = creature_traits.cost[i];
        if (creature_cost)
        {
		    t_bitmap_layer const* bitmap = m_material_icons->find( k_material_keyword[i] );

			creature_window.cost_icon[count]->set_bitmap( bitmap );
			creature_window.cost_text[count]->set_text( format_string( "%i", creature_cost ) ); 
			creature_window.cost_icon[count]->set_visible( true );
			creature_window.cost_text[count]->set_visible( true );
            count++;
        }
    }
	for (i = count; i < k_max_material_costs; ++i)
	{
		creature_window.cost_icon[i]->set_visible( false );
		creature_window.cost_text[i]->set_visible( false );
	}

	int growth = m_town->get_growth( building ) / t_town::k_population_divisor;

	if (growth < 1)
		growth = 1;
	display_text = replace_keywords( k_text_weekly_growth, "%number", 
									 format_string( "%i", growth ) );
	creature_window.creature_growth->set_text( display_text );
}

extern t_external_string const k_buy_creatures_not_owner;

// Allow creatures to be recruited.
void t_castle_window::recruit_creatures( t_button *button_ptr, int index )
{
	t_adventure_map & map = *m_town->get_map();
	int             player_number = map.get_player_number();

	if ( m_town->get_owner_number() != player_number )
	{
		ok_dialog( k_buy_creatures_not_owner, true );
		return;
	}

	t_counted_ptr<t_recruit_dialog> dialog;
    t_creature_type			creature_type = m_creature_windows[index].creature_type;
	int						limit = m_town->get_population( creature_type );
	t_material_array const& funds = m_player_ptr->get_funds();
	int						gold_cost;

	if (!check_garrison_space( m_town, creature_type ))
		return;

	gold_cost = (get_traits( creature_type ).cost[k_gold] * (100 - m_discount) + 50) / 100;
	dialog = new t_recruit_dialog( this, creature_type, limit, funds, gold_cost );
	t_sound_cache music = get_music_playing();
	stop_music();
	get_dialog_sound( k_dialog_sound_recruit )->play( get_sound_volume() );
	if (!dialog->run_modal())
	{
		play_music( music );
		return;
	}

	play_music( music );

    // Do hire.
	m_town->hire_creatures( creature_type, dialog->get_amount() );

    // Update quantity.
    update_creature_quantity( m_creature_windows[index], creature_type, 
		                    m_town->get_population( creature_type ) );

    material_update();
}

// Recruit creatures from portal.
void t_castle_window::recruit_portal( t_button *button_ptr )
{
	t_counted_ptr<t_dialog_creature_portal> dialog;
    t_creature_type creature_type = m_town->get_portal_creature();
	t_material_array const& funds = m_player_ptr->get_funds();
    
	t_adventure_map & map = *m_town->get_map();
	int             player_number = map.get_player_number();

	if ( m_town->get_owner_number() != player_number )
	{
		ok_dialog( k_buy_creatures_not_owner, true );
		return;
	}

	if (!check_garrison_space( m_town, creature_type ))
		return;

	dialog = new t_dialog_creature_portal( this, m_town, funds, m_discount );

	if (dialog->run_modal())
    {
		creature_type = dialog->get_creature_type();

	    // Player may have changed creature selection - make sure there is room...
		if (check_garrison_space( m_town, creature_type ))
			m_town->use_portal( dialog->get_amount() );
	}

    // Update quantity.
    update_creature_quantity( m_creature_windows[k_portal_number], 
							  m_town->get_portal_creature(),
                              m_town->get_portal_population() );
    update_creature_stats( m_creature_windows[k_portal_number],
						   m_town->get_portal_creature(), k_town_portal );
    material_update();
}

/*
** Clicked buy all button.
*/
void t_castle_window::purchase_all_click( t_button *button_ptr )
{
	t_material_array const& funds = m_player_ptr->get_funds();
	int player_gold_funds = m_player_ptr->get_funds()[k_gold];
    t_creature_type creature_type;
    int  creature_amount = 0;
    int creature_cost = 0;
    bool enough_creatures = false;
    bool enough_slots = false;
    bool enough_funds = false;
	std::vector<t_creature_type> creatures_recruited;
	std::vector<int> creatures_amount;
    int i;

	t_adventure_map & map = *m_town->get_map();
	int             player_number = map.get_player_number();

	if ( m_town->get_owner_number() != player_number )
	{
		ok_dialog( k_buy_creatures_not_owner, true );
		return;
	}

    // Go backwards (most expensive hire first)..
	for (i = (m_num_windows-1); i >= 0; i--)
	{
        creature_type = m_creature_windows[i].creature_type;
	    creature_amount = m_town->get_population( creature_type );
        t_creature_traits const &creature_traits = get_traits( creature_type );

        // Amount that we can add?
        if (creature_amount == 0)
            continue;
        enough_creatures = true;

        // Can we add this?
	    if (!(m_town->get_garrison().can_add( creature_type )))
            continue;
        enough_slots = true;

        // Do hire.
	    creature_amount = m_town->hire_creatures( creature_type, creature_amount );
		if (creature_amount > 0)
		{
			update_creature_quantity( m_creature_windows[i], creature_type, m_town->get_population( creature_type ) );
			enough_funds = true;
			
			creatures_recruited.push_back( creature_type );
			creatures_amount.push_back( creature_amount );
		}
	}

    /*
    ** Now add portal creature.
    */
    if (m_show_portal)
    {
        creature_type = m_town->get_portal_creature();
	    creature_amount = m_town->get_portal_population();
        t_creature_traits const &creature_traits = get_traits( creature_type );

        // Amount that we can add?
        if (creature_amount != 0)
        {
            enough_creatures = true;

            // Can we add this?
    	    if (m_town->get_garrison().can_add( creature_type ))
            {
                enough_slots = true;

                // Hire portal creature.
    	        creature_amount = m_town->use_portal( creature_amount );
				if (creature_amount > 0)
				{
	                enough_funds = true;
					creatures_recruited.push_back( creature_type );
					creatures_amount.push_back( creature_amount );
					update_creature_quantity( m_creature_windows[k_portal_number], creature_type,
									m_town->get_portal_population() );
				}
            }
        }
    }
    
    // Show dialog if can't recruit anything.
    if (enough_creatures == false)
    {
        // Not enough creatures.
	    ok_dialog( k_text_not_enough_creatures );
        return;
    }
    if (enough_slots == false)
    {
        // Not enough slots.
    	ok_dialog( k_text_not_enough_slots );
        return;
    }
    if (enough_funds == false)
    {
        // Not enough funds.
	    ok_dialog( k_text_not_enough_gold );
        return;
    }

    // Recruit successful, show creatures recruited.
    t_basic_dialog* result_dialog_ptr;
	t_screen_point point = get_mouse_screen_position();

    result_dialog_ptr = new t_basic_dialog;
    result_dialog_ptr->set_text( k_text_creatures_recruited );
	
    for (i = 0; i < creatures_recruited.size(); i++)
    {
        result_dialog_ptr->add_creature( creatures_recruited[i], creatures_amount[i], false );
    }

    result_dialog_ptr->add_ok_button();
    result_dialog_ptr->open( point, true, k_align_top );
    result_dialog_ptr->run_modal();
    material_update();
    //close();
}

/*
** Clicked close button.
*/
void t_castle_window::close_click( t_button *button_ptr )
{
	close();
}

